[beginCTF2024]Re部分WP

ezpython·

考察python的反汇编和反编译,这里使用pyinstxtractor.py进行反汇编,以及uncompyle6.pyc转为.py文件,需要注意的是从CSDN下载的脚本可能有错,导致struct.py的magic number丢失,从此处下载的可行。

然后得到ezpython.py文件。

分析文件

1
2
from gmssl import sm4
from secret import key, enc

发现使用SM4加密且从secret导入了keyenc,继续使用uncompyle6得到secret,但是结果仍然乱码,于是查看gmssl,发现key = [k ^ 37 for k in key]对key进行修改。于是还原key

1
2
key = list('BeginCTFBeginCTF')
key = "".join([chr(ord(i) ^ 37) for i in key])

再扔进cyberchef得到flag{Pay_M0re_@ttention_to_th3_key!!}

Arc·

同样是python反编译,常规步骤后得到源码。

前面的混淆看起来很唬人,但是复制运行一次就出来了,主要是后面的对比的部分难读。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 省略了,题目中复制即可
pre_list = [...]


# for i in enumerate(pre_list):
# print(i)

decimal_list = []

for sublist in pre_list:
binary_str = ''.join(str(i) for i in sublist)
decimal_list.append(int(binary_str, 2))

print(decimal_list)

flag = []

for i, _sum in enumerate(decimal_list):
for char in range(0x20, 0x80):
xor_sum = sum((char << 6) ^ (4102 - i) ^ str_begin for str_begin in b'beginCTF')
if xor_sum == _sum:
flag.append(chr(char))
break

my_flag = [str(cr) for cr in flag]
print(''.join(my_flag))

begin{Y@u_aRe_g00d_aT_play1ng_witH_sNake3}

俄语学习·

运行程序很多题,然后最后说必须全部答对才能得到flag,虽然不是很懂,但是还是patch掉再动调,得到cipher。

然后就是分析程序,发现是部分RC4算法,写出脚本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include <stdio.h>

unsigned char *Obfuscate(unsigned box[], unsigned char str[])
{
int i = 0;
int j = 0;
int k = 0;
for (i = 0; str[i] != '\0'; i++)
{
j = (j + 1) % 256;
k = (k + box[j]) % 256;
int temp = box[j];
box[j] = box[k];
box[k] = temp;
str[i] ^= box[(box[j] + box[k]) % 256];
}

return str;
}

int main()
{
unsigned box_1[] = {0x35, 0xF1, 0xDA, 0x19, 0x7A, 0xF6, 0x31, 0x9C, 0xD9, 0x2C,
0xC1, 0xFC, 0xE2, 0xD8, 0x1D, 0x8D, 0x4F, 0x97, 0x81, 0x26,
0xC0, 0xB8, 0x96, 0x27, 0xD5, 0x5B, 0xAA, 0x18, 0x85, 0xFA,
0x61, 0xE4, 0xA1, 0xBC, 0xF8, 0xA4, 0x56, 0x37, 0x43, 0x58,
0x2B, 0xC9, 0x77, 0x64, 0xCC, 0x6B, 0x98, 0x65, 0x75, 0x38,
0x80, 0x09, 0x11, 0x3D, 0xD0, 0xE6, 0x8F, 0xA9, 0x57, 0x99,
0x06, 0x10, 0x5D, 0xC5, 0x69, 0xBD, 0x2D, 0x68, 0x7E, 0xE3,
0x67, 0xD1, 0xFF, 0x5E, 0xF9, 0xF5, 0x41, 0x8C, 0xDD, 0x21,
0x4B, 0xA7, 0x47, 0x86, 0x6D, 0xC3, 0x2A, 0x9A, 0x9F, 0x20,
0x48, 0xBB, 0x94, 0xB9, 0xB4, 0x92, 0x02, 0x74, 0x7D, 0x1B,
0x1E, 0x5F, 0xBA, 0x49, 0xD6, 0xE7, 0x53, 0x04, 0xCB, 0x28,
0x3F, 0xE8, 0x33, 0x3E, 0x00, 0x9B, 0x6A, 0xFD, 0xBE, 0x1C,
0x90, 0xED, 0xDF, 0x4D, 0x25, 0x6F, 0xB5, 0x13, 0x70, 0x3C,
0x9E, 0x16, 0x0C, 0x05, 0x4A, 0x73, 0xDE, 0xB1, 0x8A, 0x51,
0x3B, 0x54, 0x14, 0xE0, 0x5A, 0xDC, 0x91, 0x62, 0xA3, 0x95,
0xD3, 0x3A, 0x17, 0xEE, 0x32, 0xF2, 0x7C, 0xAF, 0xB3, 0x88,
0xEC, 0x0E, 0xAE, 0x9D, 0x5C, 0x0D, 0x55, 0x4E, 0xFB, 0x46,
0x22, 0x44, 0x45, 0xBF, 0x52, 0x12, 0x66, 0x07, 0xD2, 0x36,
0x93, 0x6E, 0x42, 0x1A, 0x0F, 0xE9, 0x60, 0xCA, 0xB2, 0x6C,
0x83, 0xF0, 0x03, 0x76, 0xA8, 0x1F, 0x63, 0xEF, 0xA5, 0xCD,
0x79, 0x7B, 0x0A, 0x0B, 0xAB, 0xDB, 0xD4, 0x7F, 0x01, 0x34,
0x23, 0x59, 0xE1, 0x29, 0xC6, 0xAC, 0xA2, 0x40, 0xC8, 0xAD,
0xC4, 0x89, 0xC2, 0xB6, 0x71, 0xA0, 0xEB, 0x2F, 0x78, 0xF3,
0xB0, 0xFE, 0xCE, 0xF7, 0x84, 0x72, 0xF4, 0xCF, 0xC7, 0xD7,
0xB7, 0x8E, 0x4C, 0x82, 0x30, 0x50, 0x2E, 0x24, 0x87, 0x08,
0x39, 0xE5, 0xEA, 0xA6, 0x8B, 0x15};
unsigned box_2[] = {0x35, 0xF1, 0xDA, 0x19, 0x7A, 0xF6, 0x31, 0x9C, 0xD9, 0x2C,
0xC1, 0xFC, 0xE2, 0xD8, 0x1D, 0x8D, 0x4F, 0x97, 0x81, 0x26,
0xC0, 0xB8, 0x96, 0x27, 0xD5, 0x5B, 0xAA, 0x18, 0x85, 0xFA,
0x61, 0xE4, 0xA1, 0xBC, 0xF8, 0xA4, 0x56, 0x37, 0x43, 0x58,
0x2B, 0xC9, 0x77, 0x64, 0xCC, 0x6B, 0x98, 0x65, 0x75, 0x38,
0x80, 0x09, 0x11, 0x3D, 0xD0, 0xE6, 0x8F, 0xA9, 0x57, 0x99,
0x06, 0x10, 0x5D, 0xC5, 0x69, 0xBD, 0x2D, 0x68, 0x7E, 0xE3,
0x67, 0xD1, 0xFF, 0x5E, 0xF9, 0xF5, 0x41, 0x8C, 0xDD, 0x21,
0x4B, 0xA7, 0x47, 0x86, 0x6D, 0xC3, 0x2A, 0x9A, 0x9F, 0x20,
0x48, 0xBB, 0x94, 0xB9, 0xB4, 0x92, 0x02, 0x74, 0x7D, 0x1B,
0x1E, 0x5F, 0xBA, 0x49, 0xD6, 0xE7, 0x53, 0x04, 0xCB, 0x28,
0x3F, 0xE8, 0x33, 0x3E, 0x00, 0x9B, 0x6A, 0xFD, 0xBE, 0x1C,
0x90, 0xED, 0xDF, 0x4D, 0x25, 0x6F, 0xB5, 0x13, 0x70, 0x3C,
0x9E, 0x16, 0x0C, 0x05, 0x4A, 0x73, 0xDE, 0xB1, 0x8A, 0x51,
0x3B, 0x54, 0x14, 0xE0, 0x5A, 0xDC, 0x91, 0x62, 0xA3, 0x95,
0xD3, 0x3A, 0x17, 0xEE, 0x32, 0xF2, 0x7C, 0xAF, 0xB3, 0x88,
0xEC, 0x0E, 0xAE, 0x9D, 0x5C, 0x0D, 0x55, 0x4E, 0xFB, 0x46,
0x22, 0x44, 0x45, 0xBF, 0x52, 0x12, 0x66, 0x07, 0xD2, 0x36,
0x93, 0x6E, 0x42, 0x1A, 0x0F, 0xE9, 0x60, 0xCA, 0xB2, 0x6C,
0x83, 0xF0, 0x03, 0x76, 0xA8, 0x1F, 0x63, 0xEF, 0xA5, 0xCD,
0x79, 0x7B, 0x0A, 0x0B, 0xAB, 0xDB, 0xD4, 0x7F, 0x01, 0x34,
0x23, 0x59, 0xE1, 0x29, 0xC6, 0xAC, 0xA2, 0x40, 0xC8, 0xAD,
0xC4, 0x89, 0xC2, 0xB6, 0x71, 0xA0, 0xEB, 0x2F, 0x78, 0xF3,
0xB0, 0xFE, 0xCE, 0xF7, 0x84, 0x72, 0xF4, 0xCF, 0xC7, 0xD7,
0xB7, 0x8E, 0x4C, 0x82, 0x30, 0x50, 0x2E, 0x24, 0x87, 0x08,
0x39, 0xE5, 0xEA, 0xA6, 0x8B, 0x15};
unsigned char res[] = "+i&[@Y:g8[&l$f8S8v$Y&e>{";
unsigned char key_1[] =
{
0x35, 0x6D, 0x35, 0x64, 0x35, 0x77, 0x35, 0x64, 0x35, 0x62,
0x35, 0x6E, 0x35, 0x6D, 0x35, 0x64, 0x35, 0x77, 0x35, 0x64,
0x35, 0x62, 0x35, 0x6E, 0x35, 0x6D, 0x35, 0x64, 0x35, 0x77,
0x35, 0x64, 0x35, 0x62, 0x35, 0x6E, 0x8E};
int len = sizeof(res) / sizeof(res[0]) - 1;
printf("%d\n", len);
unsigned char *en_flag = Obfuscate(box_1, res);

unsigned char *de_flag = Obfuscate(box_2, en_flag);

unsigned char flag[len + 1];
for (int i = 0; i < len; i++)
{
flag[i] = de_flag[i] + 112 - key_1[i];
}
flag[len] = '\0';
printf("%s\n", flag);
}

flag{Russian_is_so_easy}

stick_game·

直接使用js反混淆工具

begin{y0u_re4l1y_g07_1337427_d0fada9dcde26b5f6bde120be1598bb7}

xor·

简单的异或加密,就是步骤有点多。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include <stdio.h>

int main()
{
char cipher[] = "`agh{^bvuwTooahlYocPtmyiijj|ek'p";
char res_1[] = "YocPtmyiijj|ek'p";
char res_2[] = "`agh{^bvuwTooahl";

int arr_1[] = {
0x36,
0x33,
0x32,
0x39,
0x30,
0x37,
0x39,
0x34,
0x32,
0x30,
0x37,
0x37,
0x31,
0x35,
0x35,
0x38,
};
int arr_2[] = {
0x37,
0x36,
0x37,
0x39,
0x36,
0x32,
0x31,
0x33,
0x38,
0x36,
0x37,
0x33,
0x35,
0x30,
0x30,
0x30,
};
int arr_3[] = {
0x34,
0x31,
0x38,
0x30,
0x33,
0x38,
0x37,
0x33,
0x36,
0x32,
0x35,
0x39,
0x30,
0x31,
0x33,
0x36,
};
int arr_4[] = {
0x33,
0x30,
0x39,
0x32,
0x36,
0x30,
0x36,
0x36,
0x33,
0x32,
0x37,
0x38,
0x37,
0x39,
0x34,
0x37,
};

for (int i = 0; i < 16; i++)
{
res_1[i] ^= arr_3[16 - i];
res_2[i] ^= arr_4[16 - i];
}
for (int i = 0; i < 16; i++)
{
res_1[i] ^= arr_4[16 - i];
res_2[i] ^= arr_3[16 - i];
}
for (int i = 0; i < 16; i++)
{
res_1[i] ^= arr_3[i];
res_2[i] ^= arr_4[i];
}
for (int i = 0; i < 16; i++)
{
res_1[i] ^= arr_4[i];
res_2[i] ^= arr_3[i];
}
for (int i = 0; i < 16; i++)
{
res_1[i] ^= arr_1[16 - i];
res_2[i] ^= arr_2[16 - i];
}
for (int i = 0; i < 16; i++)
{
res_1[i] ^= arr_2[16 - i];
res_2[i] ^= arr_1[16 - i];
}
for (int i = 0; i < 16; i++)
{
res_1[i] ^= arr_1[i];
res_2[i] ^= arr_2[i];
}
for (int i = 0; i < 16; i++)
{
res_1[i] ^= arr_2[i];
res_2[i] ^= arr_1[i];
}
char flag[32];
for (int i = 0; i < 16; i++)
{
flag[i + 16] = res_1[i];
flag[i] = res_2[i];
}
for (int i = 0; i < 32; i++)
printf("%c", flag[i]);
}

flag{Virus_gonna_be_terminated!}

babyvm·

一个虚拟机题,因为没做过,所以写得很丑陋。

先读取文件并输出指令流,分析程序意图(有部分是为了后续写解密脚本写的)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

void *memory;
uint32_t *ptr;
int len;
char input[256];
char output[256];
int in_ptr = 0;
int out_ptr = 0;
int32_t *op;

int add(int32_t *op)
{
int32_t *a1 = op + 1;
*((int32_t *)memory + *a1) = *((int32_t *)memory + a1[1]) + *((int32_t *)memory + a1[2]);
printf("add: memory[%d] = memory[%d] + memory[%d]\n", *a1, a1[1], a1[2]);
return 3;
}
int sub(int32_t *op)
{
int32_t *a1 = op + 1;
printf("\n");
printf("origin: memory[%d] = %d, memory[%d] = %d\n", a1[1], *((int32_t *)memory + a1[1]), a1[2], *((int32_t *)memory + a1[2]));
*((int32_t *)memory + *a1) = *((int32_t *)memory + a1[1]) - *((int32_t *)memory + a1[2]);
printf("sub: memory[%d] = memory[%d] - memory[%d]\n", *a1, a1[1], a1[2]);
printf("\n");
return 3;
}
int mul(int32_t *op)
{
int32_t *a1 = op + 1;
*((int32_t *)memory + *a1) = *((int32_t *)memory + a1[1]) * *((int32_t *)memory + a1[2]);
printf("origin: a1[2] = %d\n", a1[2]);
// printf("origin: memory[%d] = %d, memory[%d] = %d\n", a1[1], *((int32_t *)memory + a1[1]), a1[2], *((int32_t *)memory + a1[2]));
printf("mul: memory[%d] = memory[%d] * memory[%d]\n", *a1, a1[1], a1[2]);
return 3;
}
int my_div(int32_t *op)
{
int32_t *a1 = op + 1;
if (!*((int32_t *)memory + 2))
{
*((int32_t *)memory + *a1) = *((int32_t *)memory + a1[1]) / *((int32_t *)memory + a1[2]);
printf("div: memory[%d] = memory[%d] / memory[%d]\n", *a1, a1[1], a1[2]);
}
return 3;
}
int rst_in(int32_t *op)
{
in_ptr = 0;
printf("in_ptr = 0\n");
return 0;
}
int rst_out(int32_t *op)
{
out_ptr = 0;
printf("out_ptr = 0\n");
return 0;
}
int pop_in(int32_t *op)
{
int32_t *a1 = op + 1;
int v2;
int i;
for (i = 0; i < a1[1]; i++)
{
v2 = in_ptr++;
*((int32_t *)memory + *a1 + i) = input[v2];
printf("pop_in: memory[%d] = input[%d]\n", *a1 + i, v2);
}
return 2;
}
int pop_out(int32_t *op)
{
int32_t *a1 = op + 1;
int v2;
int i;
for (i = 0; i < a1[1]; i++)
{
v2 = out_ptr++;
output[v2] = *((int32_t *)memory + *a1 + i);
printf("pop_out: output[%d] = memory[%d]\n", v2, *a1 + i);
}
return 2;
}
int read_buf(int32_t *op)
{
int32_t *a1 = op + 1;
if (*a1 <= 0xC7)
fgets(input, *a1, stdin);
printf("read_buf: input = %s\n", input);
return 1;
}
int write_buf(int32_t *op, char **out)
{
int32_t *a1 = op + 1;
if (*a1 < 0xC7)
printf("%s", *out);
return 1;
}
int jmp(int32_t *op)
{
int32_t *a1 = op + 1;
if (a1[1] && !*((int32_t *)memory + a1[1]))
{
printf("jmp: jump following %d\n", 2);
return 2;
}
else
{
printf("jmp: jump following %d\n", *a1);
return *a1;
}
}
int njmp(int32_t *op)
{
int32_t *a1 = op + 1;
printf("njmp: memory[%d] = %d\n", a1[1], *((int32_t *)memory + a1[1]));
printf("njmp: memory[900] = %d\n", *((int32_t *)memory + 900));
if (a1[1] && *((int32_t *)memory + a1[1]))
{
printf("njmp: jump following %d\n", 2);
return 2;
}
else
{
printf("njmp: jump following %d\n", *a1);
return *a1;
}
}
int my_len(int32_t *op)
{
int32_t *a1 = op + 1;
char s[200] = {0}; // 初始化数组,确保所有元素都是零
int32_t v4 = 0;
int32_t *v5 = (int32_t *)((char *)memory + 4 * *a1);
printf("v5: %c\n", *v5);
while (*v5)
{
s[v4++] = (char)*v5++; // 读取v5指向的值,并将其转换为字符,然后存储在s中
}
*((int32_t *)memory + a1[1]) = strlen(s);
printf("len: memory[%d] = %d\n", *a1, strlen(s));
return 2;
}

int main()
{
setbuf(stdin, 0LL);
setbuf(stdout, 0LL);

FILE *stream1;
FILE *stream2;
stream1 = fopen("op.vm", "r");
stream2 = fopen("memory.vm", "r");
if (!stream1 || !stream2)
{
puts("Cannot open file!");
exit(1);
}
len = 14640;
ptr = malloc(len);
memory = malloc(0x3000uLL);

if (!ptr || !memory)
{
puts("Cannot allocate memory!");
exit(1);
}
size_t num_read = fread(ptr, 1, len / sizeof(int), stream1);
fread(memory, 4, 0x1030, stream2);
fclose(stream1);
fclose(stream2);


for (int j = 0; j < 20; j++)
{
printf("Y%d = [", j + 1);
for (int i = 1000 + j; i <= 1380 + j; i += 20)
{
printf("%d, ", *((int32_t *)memory + i));
}
printf("]\n");
}
for (int j = 0; j < 20; j++)
{
// s.add(_sum1 == 217114)
printf("s.add(_sum%d == %d)\n", j + 1, *((int32_t *)memory + 5 + j));
}

op = ptr;
char *out = output;

while (op >= ptr && *op)
{
switch (*op)
{
case 1:
op += add(op) + 1;
break;
case 2:
op += sub(op) + 1;
break;
case 3:
op += mul(op) + 1;
break;
case 4:
op += my_div(op) + 1;
break;
case 5:
op += rst_in(op) + 1;
break;
case 6:
op += rst_out(op) + 1;
break;
case 7:
op += pop_in(op) + 1;
break;
case 8:
op += pop_out(op) + 1;
break;
case 9:
op += read_buf(op) + 1;
break;
case 0xA:
op += write_buf(op, &out) + 1;
break;
case 0xB:
op += jmp(op) + 1;
break;
case 0xC:
op += njmp(op) + 1;
break;
case 0xD:
op += my_len(op) + 1;
break;
default:
printf("Unknown op: %d\n", *op);
exit(1);
}
}

return 0;
}

随便输入一个begin{114514},发现会先比较flag头和尾,再验证flag长度,如果正确再将flag的内容进行累乘再累加,最后和一个数字比较。

刚开始想着爆破,但是显然行不通,于是先得出一个可能解,输入后发现进行了第二轮验证,想到应该是解多元一次方程,所以拿出z3。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
from z3 import *


X = [Int('x%s' % i) for i in range(20)]
Y1 = [115, 26, 128, 200, 21, 234, 172, 152, 39, 71, 55, 28, 105, 42, 75, 63, 114, 205, 2, 222, ]
Y2 = [212, 148, 17, 74, 87, 253, 250, 136, 89, 211, 49, 26, 115, 88, 181, 195, 237, 10, 119, 121, ]
Y3 = [229, 172, 230, 123, 245, 127, 119, 157, 208, 159, 37, 32, 5, 207, 145, 75, 251, 60, 135, 125, ]
Y4 = [181, 83, 66, 43, 85, 198, 89, 205, 114, 221, 105, 145, 155, 91, 123, 48, 76, 64, 141, 22, ]
Y5 = [211, 225, 204, 55, 107, 76, 7, 39, 199, 84, 167, 62, 219, 54, 6, 144, 55, 98, 186, 116, ]
Y6 = [149, 163, 127, 186, 46, 118, 247, 194, 9, 165, 169, 224, 68, 129, 54, 15, 134, 39, 185, 248, ]
Y7 = [245, 159, 64, 241, 163, 116, 4, 15, 126, 170, 10, 110, 251, 169, 252, 99, 199, 188, 149, 72, ]
Y8 = [233, 38, 197, 105, 202, 2, 22, 225, 189, 166, 239, 220, 70, 98, 194, 129, 27, 236, 159, 62, ]
Y9 = [152, 67, 72, 35, 12, 55, 139, 4, 169, 142, 135, 122, 3, 166, 139, 62, 23, 92, 11, 136, ]
Y10 = [96, 141, 38, 124, 139, 43, 15, 119, 30, 252, 255, 123, 223, 200, 21, 117, 231, 9, 239, 222, ]
Y11 = [249, 91, 66, 21, 121, 146, 5, 180, 6, 80, 112, 255, 239, 17, 39, 254, 153, 118, 47, 217, ]
Y12 = [84, 96, 190, 188, 255, 181, 188, 124, 47, 70, 201, 160, 126, 210, 236, 22, 120, 181, 197, 69, ]
Y13 = [51, 173, 216, 143, 41, 174, 184, 189, 111, 133, 79, 36, 99, 140, 120, 144, 80, 231, 187, 107, ]
Y14 = [173, 39, 151, 161, 139, 233, 143, 205, 170, 125, 209, 54, 128, 134, 55, 246, 157, 57, 42, 195, ]
Y15 = [5, 49, 235, 8, 84, 9, 219, 90, 109, 164, 38, 159, 218, 214, 22, 205, 7, 57, 210, 131, ]
Y16 = [107, 67, 107, 141, 129, 250, 97, 3, 26, 215, 119, 213, 255, 183, 229, 1, 27, 9, 88, 59, ]
Y17 = [57, 72, 91, 96, 125, 105, 94, 235, 138, 39, 145, 130, 126, 147, 254, 179, 181, 183, 216, 211, ]
Y18 = [164, 205, 28, 160, 233, 70, 109, 51, 0, 71, 99, 163, 37, 98, 46, 44, 138, 135, 191, 144, ]
Y19 = [13, 240, 143, 53, 75, 23, 26, 224, 31, 199, 182, 220, 130, 61, 170, 130, 253, 240, 182, 9, ]
Y20 = [245, 96, 170, 79, 249, 16, 121, 6, 7, 69, 212, 133, 52, 20, 225, 102, 228, 121, 56, 208, ]


s = Solver() # 创建一个Solver实例
for i in range(20):
s.add(And(0x20 < X[i], X[i] < 0x80)) # 使用And函数合并两个条件

_sum1 = sum(X[i] * Y1[i] for i in range(20))
_sum2 = sum(X[i] * Y2[i] for i in range(20))
_sum3 = sum(X[i] * Y3[i] for i in range(20))
_sum4 = sum(X[i] * Y4[i] for i in range(20))
_sum5 = sum(X[i] * Y5[i] for i in range(20))
_sum6 = sum(X[i] * Y6[i] for i in range(20))
_sum7 = sum(X[i] * Y7[i] for i in range(20))
_sum8 = sum(X[i] * Y8[i] for i in range(20))
_sum9 = sum(X[i] * Y9[i] for i in range(20))
_sum10 = sum(X[i] * Y10[i] for i in range(20))
_sum11 = sum(X[i] * Y11[i] for i in range(20))
_sum12 = sum(X[i] * Y12[i] for i in range(20))
_sum13 = sum(X[i] * Y13[i] for i in range(20))
_sum14 = sum(X[i] * Y14[i] for i in range(20))
_sum15 = sum(X[i] * Y15[i] for i in range(20))
_sum16 = sum(X[i] * Y16[i] for i in range(20))
_sum17 = sum(X[i] * Y17[i] for i in range(20))
_sum18 = sum(X[i] * Y18[i] for i in range(20))
_sum19 = sum(X[i] * Y19[i] for i in range(20))
_sum20 = sum(X[i] * Y20[i] for i in range(20))
s.add(_sum1 == 217114)
s.add(_sum2 == 270581)
s.add(_sum3 == 291585)
s.add(_sum4 == 234325)
s.add(_sum5 == 240502)
s.add(_sum6 == 277604)
s.add(_sum7 == 286168)
s.add(_sum8 == 290450)
s.add(_sum9 == 179355)
s.add(_sum10 == 272487)
s.add(_sum11 == 249816)
s.add(_sum12 == 305636)
s.add(_sum13 == 276217)
s.add(_sum14 == 294166)
s.add(_sum15 == 237236)
s.add(_sum16 == 242008)
s.add(_sum17 == 289929)
s.add(_sum18 == 221788)
s.add(_sum19 == 268459)
s.add(_sum20 == 247407)


while s.check() == sat: # 检查解是否满足
m = s.model()
solution = ""
for i in range(20):
solution += chr(m[X[i]].as_long()) # 直接使用m[X[i]].as_long()转换为整数
print(solution)

# 添加新的约束来排除当前的解
s.add(Or([X[i] != m[X[i]] for i in range(20)]))

begin{have_fun_in_vm_hahaa}

dragon·

安卓逆向题

肯定是非预期解了,注意到encrypt1encrypt2两个关键环节,其中encrypt2进行了简单的乱序混淆之后将字符串转化为16进制串,问题在于encrypt1里面进行乱序的KEY是未知的,所以直接将16进制串转为字符串,然后乱拼。

这样可行的原因有两点,首先,encrypt1是将32byte的字符串分为两组进行加密,所以前后两组的打乱顺序一致,其次,flag的头尾已知,且最后pad了几个0,所以排序的约束条件多了很多。

先将encrypt2进行解密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>



int main()
{
int S_BOX[] = {9, 11, 25, 20, 15, 30, 24, 23, 2, 26, 28, 13, 16, 19, 29, 31, 5, 4, 17, 12, 14, 8, 27, 21, 22, 3, 7, 0, 18, 6, 10, 1};
int B_BOX[] = {17, 41, 19, 23, 47, 2, 3, 7, 29, 53, 31, 5, 43, 11, 37, 13};

const char cipher[] = "697B62696563660000750069616C66006C6E006C765F65656769656F7D4E7474";
int str_len = strlen(cipher);
int len = str_len / 2;
int en_cipher[32];
int de_cipher[32];
int i;
for (i = 0; i < len; i++)
{
sscanf(cipher + 2 * i, "%2X", &en_cipher[i]);
}
for (int j = 0; j < 16; j++)
{
for (i = 0; i < len; i++)
{
de_cipher[S_BOX[i]] = en_cipher[i];
}
for (i = 0; i < len; i++)
{
en_cipher[i] = de_cipher[i];
}
}
for (i = 0; i < len; i++)
{
if (de_cipher[i] == 0)
{
printf("?");
}
if (i == 16)
printf("\n");
printf("%c ", de_cipher[i]);
}
printf("\n");
return 0;
}

得到

1
2
u t i v n l g e b e t { l i N e 
a ? } l f ? o _ e i ? i ? f c ?

问号一定在末尾,begin{}是确定的,且上下同时移动,最后在原神玩家的帮助下得到了begin{Neuvillette_official}

红白机·

用的是FC的6502指令集,写出脚本即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
class Simplified6502:
def __init__(self):
self.memory = [1] * 0x10000
self.reg_a = 0
self.reg_x = 0

def lda_imm(self, value):
self.reg_a = value

def ldx_imm(self, value):
self.reg_x = value

def sta_abs(self, addr):
self.memory[addr + self.reg_x] = self.reg_a

def inx(self):
self.reg_x = (self.reg_x + 1) & 0xff

def execute(self, instruction):
parts = instruction.split()
if parts[0] == 'LDA':
digits = [c for c in parts[1] if c.isdigit()]
number = "".join(digits)
self.lda_imm(int(number, 16))
elif parts[0] == 'LDX':
number = parts[1].replace("#$", "")
self.ldx_imm(int(number, 16))
elif parts[0] == 'STA':
digits = [c for c in parts[1] if c.isdigit()]
number = "".join(digits)
self.sta_abs(int(number, 16))
elif parts[0] == 'INX':
self.inx()


cpu = Simplified6502()

with open('6502.txt', 'r') as file:
instructions = file.readlines()

for instruction in instructions:
cpu.execute(instruction.strip())

for i in range(0x200,0x5ff):
if (i%0x20) == 0:
print()
if cpu.memory[i] == 0:
print('▰',end=' ')
elif cpu.memory[i] == 1:
print('▱',end=' ')

flag{6502_I_LOVE_u}